using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System.Threading;

namespace codebase
{
    class SRAM
    {
        //hold pin 7 = high
        const uint SRAM_SIZE = 32768;

        enum Command
        {
            Read = 0x03,
            Write = 0x02,
            RDSR = 0x05,
            WRSR = 0x01,
        };

        //hold is disabled
        enum Mode
        {
            Byte = 0x01,
            Page = 0x81,
            Sequential = 0x41,
        };

        SPI _spi;

        public SRAM(SPI _spi)
        {
            this._spi = _spi;
            SetMode(Mode.Sequential);
            CheckStatus();
        }

        //quick check using a couple read/writes
        private void CheckStatus()
        {
            WriteByte(0, 100);
            WriteByte(SRAM_SIZE - 1, 100);
            WriteByte(0, 128);
            WriteByte(SRAM_SIZE - 1, 192);
            byte b1 = ReadByte(0);
            byte b2 = ReadByte(SRAM_SIZE - 1);
            if (b1 == 128 && b2 == 192)
            {
                Debug.Print("SRAM Found");
            }
            else
            {
                Debug.Print("SRAM Error");
                Thread.Sleep(5000);
            }
        }

        private void SetMode(Mode val)
        {
            byte[] output = new byte[2];
            output[0] = (byte)Command.WRSR;
            output[1] = (byte)val;
            _spi.Write(output);
        }

        public byte WriteByte(uint addr, byte val)
        {
            if (addr >= SRAM_SIZE)
            {
                return 0xFF;
            }
            byte[] output = new byte[4];
            output[0] = (byte)Command.Write;
            output[1] = (byte)(addr >> 8);
            output[2] = (byte)(addr & 0xFF);
            output[3] = val;
            _spi.Write(output);
            return 0;
        }

        public byte ReadByte(uint addr)
        {
            if (addr >= SRAM_SIZE)
            {
                return 0xFF;
            }
            byte[] output = new byte[3];
            byte[] input = new byte[1];
            output[0] = (byte)Command.Read;
            output[1] = (byte)(addr >> 8);
            output[2] = (byte)(addr & 0xFF);
            _spi.WriteRead(output, 0, 3, input, 0, 1, 3);
            return input[0];
        }

        public byte WriteBuffer(uint addr, byte[] buffer)
        {
            if (addr + buffer.Length >= SRAM_SIZE)
            {
                return 0xFF;
            }
            else
            {
                byte[] output = new byte[3 + buffer.Length];
                output[0] = (byte)Command.Write;
                output[1] = (byte)(addr >> 8);
                output[2] = (byte)(addr & 0xFF);
                Array.Copy(buffer, 0, output, 3, buffer.Length);
                _spi.Write(output);
                return 0;
            }
        }

        public byte[] ReadBuffer(uint addr, int count)
        {
            if (addr + count >= SRAM_SIZE)
            {
                count = (int)(SRAM_SIZE - addr);
            }
            byte[] output = new byte[3];
            byte[] input = new byte[count];
            output[0] = (byte)Command.Read;
            output[1] = (byte)(addr >> 8);
            output[2] = (byte)(addr & 0xFF);
            _spi.WriteRead(output, 0, 3, input, 0, count, 3);
            return input;
        }

    }
}
